package com.liuche.homechat.common.user.service.impl;

import com.liuche.homechat.common.common.constant.RedisKeyConstant;
import com.liuche.homechat.common.user.service.LoginService;
import com.liuche.homechat.common.common.utils.JwtUtils;
import com.liuche.homechat.common.common.utils.RedisUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @author：liuche
 * @Date：2024年06月01日 14:38
 * @Description：
 */
@Service
public class LoginServiceImpl implements LoginService {
    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private JwtUtils jwtUtils;

    private static final long TOKEN_EXPIRED_TIME = 30 * 24 * 60 * 60L; // 三天有效期
    private static final long TOKEN_MAX_RENEWAL_TIME = 20 * 24 * 60 * 60L; // 最大过期时间

    @Override
    public boolean verify(String token) {
        Long uid = jwtUtils.getUidOrNull(token);
        if (ObjectUtils.isNotEmpty(uid)) {
            // 校验当前 token 是否合法
            String key = getRedisLoginKey(uid);
            String newToken = redisTemplate.opsForValue().get(key);
            return ObjectUtils.isNotEmpty(newToken) && token.equals(newToken);
        }
        return false;
    }

    @Override
    @Async
    public void renewalTokenIfNecessary(String token) {
        Long uid = getValidUid(token);
        String loginKey = getRedisLoginKey(uid);
        if (ObjectUtils.isEmpty(uid)) {
            return;
        }
        // 从 redis 中获取 token
        Long expireTime = RedisUtils.getExpire(loginKey, TimeUnit.SECONDS);

        // 如果过期时间小于一天
        if (TOKEN_MAX_RENEWAL_TIME > expireTime) {
            // 续期
            RedisUtils.expire(loginKey, TOKEN_EXPIRED_TIME, TimeUnit.SECONDS);
        }
    }

    @Override
    public String login(Long uid) {
        String loginKey = getRedisLoginKey(uid);

        // 做层校验：判断 redis 中是否以经有用户的 token
        String token = redisTemplate.opsForValue().get(loginKey);
        if (StringUtils.isNotBlank(token)) {
            return token;
        }

        // 生成 token，返回并保存
        token = jwtUtils.createToken(uid);
        redisTemplate.opsForValue().set(loginKey, token, TOKEN_EXPIRED_TIME, TimeUnit.SECONDS);

        return token;
    }

    @Override
    public Long getValidUid(String token) {
        Long uid = jwtUtils.getUidOrNull(token);
        if (ObjectUtils.isNotEmpty(uid)) {
            // 校验当前 token 是否合法
            String key = getRedisLoginKey(uid);
            String newToken = redisTemplate.opsForValue().get(key);
            if (ObjectUtils.isNotEmpty(newToken) && token.equals(newToken)) {
                return uid;
            }
        }

        return null;
    }


    private String getRedisLoginKey(Long uid) {
        return RedisKeyConstant.getKey(RedisKeyConstant.USER_LOGIN_KEY, uid);
    }
}
